/*
 * Created by Jaren at 2021/10/29 11:38
 */
import 'dart:typed_data';

import 'package:binary/binary.dart';
import 'package:inmotion_protocol/common/exceptions.dart';
import 'package:inmotion_protocol/elephant/model.dart';
import 'package:inmotion_protocol/ezcan/ezcan_model.dart';
import 'package:inmotion_protocol/util/byte_util.dart';

class ProductModel {
  static const minLength = 6;

  Uint8 mainSeries = Uint8.zero;
  Uint8 series = Uint8.zero;
  Uint8 type = Uint8.zero;
  Uint8 batch = Uint8.zero;
  Uint8 feature = Uint8.zero;
  Uint8 reverse = Uint8.zero;

  String originCarType = '';
  String hexCode = '';

  ProductModel(this.mainSeries, this.series, this.type, this.batch,
      this.feature, this.reverse) {
    hexCode = ByteUtil.byte2Hex(mainSeries.value) +
        ByteUtil.byte2Hex(series.value) +
        ByteUtil.byte2Hex(type.value) +
        ByteUtil.byte2Hex(batch.value) +
        ByteUtil.byte2Hex(feature.value) +
        ByteUtil.byte2Hex(reverse.value);
  }

  ProductModel.from(List<String> data) {
    if (data.length >= 6) {
      mainSeries = ByteUtil.toUint8(int.parse(data[0]));
      series = ByteUtil.toUint8(int.parse(data[1]));
      type = ByteUtil.toUint8(int.parse(data[2]));
      batch = ByteUtil.toUint8(int.parse(data[3]));
      feature = ByteUtil.toUint8(int.parse(data[4]));
      reverse = ByteUtil.toUint8(int.parse(data[5]));

      hexCode = ByteUtil.byte2Hex(mainSeries.value) +
          ByteUtil.byte2Hex(series.value) +
          ByteUtil.byte2Hex(type.value) +
          ByteUtil.byte2Hex(batch.value) +
          ByteUtil.byte2Hex(feature.value) +
          ByteUtil.byte2Hex(reverse.value);
    }
  }

  ProductModel.fromEzcan(Uint8ClampedList bytes, [int offset = 0]) {
    int modelInt = ByteUtil.bytes2IntLe(bytes, offset, 4);
    switch (modelInt) {
      /* V8 START */
      case EzcanModel.V8:
        mainSeries = ByteUtil.toUint8(euc);
        series = ByteUtil.toUint8(V8);
        type = ByteUtil.toUint8(1);
        break;
      case EzcanModel.GLIDE3:
        mainSeries = ByteUtil.toUint8(euc);
        series = ByteUtil.toUint8(V8);
        type = ByteUtil.toUint8(2);
        break;
      case EzcanModel.V8F:
        mainSeries = ByteUtil.toUint8(euc);
        series = ByteUtil.toUint8(V8);
        type = ByteUtil.toUint8(3);
        break;
      case EzcanModel.V8S:
        mainSeries = ByteUtil.toUint8(euc);
        series = ByteUtil.toUint8(V8);
        type = ByteUtil.toUint8(4);
        break;
      /* V8 END */

      /* V10 START */
      case EzcanModel.V10:
        mainSeries = ByteUtil.toUint8(euc);
        series = ByteUtil.toUint8(V10);
        type = ByteUtil.toUint8(3);
        break;
      case EzcanModel.V10F:
        mainSeries = ByteUtil.toUint8(euc);
        series = ByteUtil.toUint8(V10);
        type = ByteUtil.toUint8(4);
        break;
      /* V10 END */

      /* V5 START */
      case EzcanModel.V5:
        mainSeries = ByteUtil.toUint8(euc);
        series = ByteUtil.toUint8(V5);
        type = ByteUtil.toUint8(1);
        break;
      case EzcanModel.V5PLUS:
        mainSeries = ByteUtil.toUint8(euc);
        series = ByteUtil.toUint8(V5);
        type = ByteUtil.toUint8(2);
        break;
      case EzcanModel.V5F:
        mainSeries = ByteUtil.toUint8(euc);
        series = ByteUtil.toUint8(V5);
        type = ByteUtil.toUint8(3);
        break;
      case EzcanModel.V5D:
        mainSeries = ByteUtil.toUint8(euc);
        series = ByteUtil.toUint8(V5);
        type = ByteUtil.toUint8(4);
        break;
      case EzcanModel.GLIDE2:
        mainSeries = ByteUtil.toUint8(euc);
        series = ByteUtil.toUint8(V5);
        type = ByteUtil.toUint8(5);
        break;
      case EzcanModel.GLIDE2_L:
        mainSeries = ByteUtil.toUint8(euc);
        series = ByteUtil.toUint8(V5);
        type = ByteUtil.toUint8(6);
        break;
      case EzcanModel.V5SE:
        mainSeries = ByteUtil.toUint8(euc);
        series = ByteUtil.toUint8(V5);
        type = ByteUtil.toUint8(7);
        break;
      case EzcanModel.V5E:
        mainSeries = ByteUtil.toUint8(euc);
        series = ByteUtil.toUint8(V5);
        type = ByteUtil.toUint8(8);
        break;
      case EzcanModel.V5C:
        mainSeries = ByteUtil.toUint8(euc);
        series = ByteUtil.toUint8(V5);
        type = ByteUtil.toUint8(9);
        break;
      /*  ByteUtil.toUint8(V5); END */

      /* P1 START */
      case EzcanModel.P1:
        mainSeries = ByteUtil.toUint8(eBike);
        series = ByteUtil.toUint8(P1);
        type = ByteUtil.toUint8(1);
        break;
      case EzcanModel.P1F:
        mainSeries = ByteUtil.toUint8(eBike);
        series = ByteUtil.toUint8(P1);
        type = ByteUtil.toUint8(2);
        break;
      case EzcanModel.P1SE:
        mainSeries = ByteUtil.toUint8(eBike);
        series = ByteUtil.toUint8(P1);
        type = ByteUtil.toUint8(3);
        break;
      case EzcanModel.P1H:
        mainSeries = ByteUtil.toUint8(eBike);
        series = ByteUtil.toUint8(P1);
        type = ByteUtil.toUint8(4);
        break;
      /* P1 END */

      /* P2 START */
      case EzcanModel.P2:
        mainSeries = ByteUtil.toUint8(eBike);
        series = ByteUtil.toUint8(P2);
        type = ByteUtil.toUint8(1);
        break;
      case EzcanModel.P2F:
        mainSeries = ByteUtil.toUint8(eBike);
        series = ByteUtil.toUint8(P2);
        type = ByteUtil.toUint8(2);
        break;
      case EzcanModel.P2LUXURY:
        mainSeries = ByteUtil.toUint8(eBike);
        series = ByteUtil.toUint8(P2);
        type = ByteUtil.toUint8(3);
        break;
      case EzcanModel.P2YOUTH:
        mainSeries = ByteUtil.toUint8(eBike);
        series = ByteUtil.toUint8(P2);
        type = ByteUtil.toUint8(4);
        break;
      case EzcanModel.P2S:
        mainSeries = ByteUtil.toUint8(eBike);
        series = ByteUtil.toUint8(P2);
        type = ByteUtil.toUint8(5);
        break;
      /* P2 END */

      /* L8 START */
      case EzcanModel.L8:
        mainSeries = ByteUtil.toUint8(scooter);
        series = ByteUtil.toUint8(L8);
        type = ByteUtil.toUint8(1);
        break;
      case EzcanModel.L8F:
        mainSeries = ByteUtil.toUint8(scooter);
        series = ByteUtil.toUint8(L8);
        type = ByteUtil.toUint8(2);
        break;
      case EzcanModel.L8F_CH:
        mainSeries = ByteUtil.toUint8(scooter);
        series = ByteUtil.toUint8(L8);
        type = ByteUtil.toUint8(3);
        break;
      case EzcanModel.L8F_NO:
        mainSeries = ByteUtil.toUint8(scooter);
        series = ByteUtil.toUint8(L8);
        type = ByteUtil.toUint8(4);
        break;
      case EzcanModel.L8D:
        mainSeries = ByteUtil.toUint8(scooter);
        series = ByteUtil.toUint8(L8);
        type = ByteUtil.toUint8(5);
        break;
      case EzcanModel.L8S:
        mainSeries = ByteUtil.toUint8(scooter);
        series = ByteUtil.toUint8(L8);
        type = ByteUtil.toUint8(6);
        break;
      case EzcanModel.L8S_PLUS:
        mainSeries = ByteUtil.toUint8(scooter);
        series = ByteUtil.toUint8(L8);
        type = ByteUtil.toUint8(7);
        break;
      case EzcanModel.L8DF:
        mainSeries = ByteUtil.toUint8(scooter);
        series = ByteUtil.toUint8(L8);
        type = ByteUtil.toUint8(8);
        break;
      case EzcanModel.L8_NO:
        mainSeries = ByteUtil.toUint8(scooter);
        series = ByteUtil.toUint8(L8);
        type = ByteUtil.toUint8(9);
        break;
      /* L8 END */
    }
    if (mainSeries.value == 0) {
      if (EzcanModel.isV5(modelInt)) {
        mainSeries = ByteUtil.toUint8(euc);
        series = ByteUtil.toUint8(V5);
        type = ByteUtil.toUint8(1);
      } else if (EzcanModel.isV8(modelInt)) {
        mainSeries = ByteUtil.toUint8(euc);
        series = ByteUtil.toUint8(V8);
        type = ByteUtil.toUint8(1);
      } else if (EzcanModel.isV10(modelInt)) {
        mainSeries = ByteUtil.toUint8(euc);
        series = ByteUtil.toUint8(V10);
        type = ByteUtil.toUint8(1);
      } else if (EzcanModel.isP1(modelInt)) {
        mainSeries = ByteUtil.toUint8(eBike);
        series = ByteUtil.toUint8(P1);
        type = ByteUtil.toUint8(1);
      } else if (EzcanModel.isP2(modelInt)) {
        mainSeries = ByteUtil.toUint8(eBike);
        series = ByteUtil.toUint8(P2);
        type = ByteUtil.toUint8(1);
      } else if (EzcanModel.isL8(modelInt)) {
        mainSeries = ByteUtil.toUint8(scooter);
        series = ByteUtil.toUint8(L8);
        type = ByteUtil.toUint8(1);
      } else if (EzcanModel.isR1(modelInt)) {
        mainSeries = ByteUtil.toUint8(dulWheelScv);
        series = ByteUtil.toUint8(R1);
        type = ByteUtil.toUint8(1);
      } else {
        throw NotSupportException('Unknown model [$modelInt].');
      }
    }
    batch = ByteUtil.toUint8(1);
    feature = ByteUtil.toUint8(1);

    originCarType = ByteUtil.bytes2HexString(ByteUtil.num2BytesLe(modelInt, 4));
    hexCode = ByteUtil.byte2Hex(mainSeries.value) +
        ByteUtil.byte2Hex(series.value) +
        ByteUtil.byte2Hex(type.value) +
        ByteUtil.byte2Hex(batch.value) +
        ByteUtil.byte2Hex(feature.value) +
        ByteUtil.byte2Hex(reverse.value);
  }

  ProductModel.fromElephant(Uint8ClampedList bytes, [int offset = 0]) {
    int modelInt = ByteUtil.bytes2IntLe(bytes, offset, 4);
    switch (modelInt) {
      case ElephantModel.E2:
      case ElephantModel.E2_R0:
        mainSeries = ByteUtil.toUint8(dulWheelScv);
        series = ByteUtil.toUint8(E2);
        type = ByteUtil.toUint8(1);
        break;
      case ElephantModel.E2P:
        mainSeries = ByteUtil.toUint8(dulWheelScv);
        series = ByteUtil.toUint8(E2);
        type = ByteUtil.toUint8(2);
        break;
      case ElephantModel.E2Lite:
        mainSeries = ByteUtil.toUint8(dulWheelScv);
        series = ByteUtil.toUint8(E2);
        type = ByteUtil.toUint8(3);
        break;
      case ElephantModel.E3:
        mainSeries = ByteUtil.toUint8(dulWheelScv);
        series = ByteUtil.toUint8(E3);
        type = ByteUtil.toUint8(1);
        break;
      case ElephantModel.E3Lite:
        mainSeries = ByteUtil.toUint8(dulWheelScv);
        series = ByteUtil.toUint8(E3);
        type = ByteUtil.toUint8(2);
        break;
      default:
        throw NotSupportException('Unknown model [$modelInt].');
    }
    batch = ByteUtil.toUint8(1);
    feature = ByteUtil.toUint8(1);

    originCarType = ByteUtil.bytes2HexString(ByteUtil.num2BytesLe(modelInt, 4));
    hexCode = ByteUtil.byte2Hex(mainSeries.value) +
        ByteUtil.byte2Hex(series.value) +
        ByteUtil.byte2Hex(type.value) +
        ByteUtil.byte2Hex(batch.value) +
        ByteUtil.byte2Hex(feature.value) +
        ByteUtil.byte2Hex(reverse.value);
  }

  ProductModel.fromHexCode(this.hexCode) {
    if (hexCode.length != minLength * 2)
      throw NotSupportException('Unknown model $hexCode');
    mainSeries = ByteUtil.hexStr2Byte(hexCode, 0, 2);
    series = ByteUtil.hexStr2Byte(hexCode, 2, 2);
    type = ByteUtil.hexStr2Byte(hexCode, 4, 2);
    batch = ByteUtil.hexStr2Byte(hexCode, 6, 2);
    feature = ByteUtil.hexStr2Byte(hexCode, 8, 2);
    reverse = ByteUtil.hexStr2Byte(hexCode, 10, 2);
  }

  static final ProductModel unknown = ProductModel(
      Uint8.zero, Uint8.zero, Uint8.zero, Uint8.zero, Uint8.zero, Uint8.zero);

  @override
  bool operator ==(Object other) =>
      identical(this, other) ||
      other is ProductModel &&
          runtimeType == other.runtimeType &&
          mainSeries == other.mainSeries &&
          series == other.series &&
          type == other.type &&
          batch == other.batch &&
          feature == other.feature &&
          reverse == other.reverse &&
          originCarType == other.originCarType &&
          hexCode == other.hexCode;

  @override
  int get hashCode =>
      mainSeries.hashCode ^
      series.hashCode ^
      type.hashCode ^
      batch.hashCode ^
      feature.hashCode ^
      reverse.hashCode ^
      originCarType.hashCode ^
      hexCode.hashCode;

  @override
  String toString() {
    return 'ProductModel{hexCode: $hexCode}';
  }

  ///    主系列 START    ///
  static const int dulWheelScv = 1; // 双轮平衡车
  static const int euc = 2; // 独轮平衡车
  static const int scooter = 3; // 电动滑板车
  static const int eBike = 4; // 电动车
  static const int wiggle = 5; // 扭扭车
  ///    主系列 END    ///

  ///    子系列 START ///

  // 双轮系列
  static const int R1 = 1;
  static const int E2 = 3;
  static const int E3 = 4;

  // 独轮系列
  static const int V5 = 3;
  static const int V8 = 4;
  static const int V10 = 5;
  static const int V11 = 6;
  static const int V12 = 7;
  static const int V13 = 8;
  static const int V14 = 9;
  static const int E20 = 10;
  static const int V12S = 11;
  static const int V9 = 12;
  static const int P6 = 13;
  static const int V6 = 14;
  static const int E10 = 15;
  static const int E15 = 16;

  // 滑板系列
  static const int L8 = 4;
  static const int LS1 = 5;
  static const int LA1 = 6;
  static const int LC1 = 7;
  static const int LE1 = 8;
  static const int LR1 = 9;
  static const int RS_VELO = 10;

  // 电动车系列
  static const int P1 = 1;
  static const int P2 = 2;
  static const int P3 = 3;

  // 扭扭车系列
//    static const int C1 = 1;
//    static const int C3 = 2;
//    static const int D1 = 3;
//    static const int D2 = 4;
//    static const int B2 = 5;
  ///     子系列 END     ///

  bool isEzCANModel() {
    return isV5Series() ||
        isV8Series() ||
        isV10Series() ||
        isL8Series() ||
        isP1Series() ||
        isP2Series() ||
        isR1Series();
  }

  bool isLorinModel() {
    return !isEzCANModel() && !isElephantModel();
  }

  bool isElephantModel() {
    return isE2Series() || isE3Series();
  }

  bool isEBike() {
    return mainSeries.value == eBike;
  }

  bool isEuc() {
    return mainSeries.value == euc;
  }

  bool isScooter() {
    return mainSeries.value == scooter;
  }

  bool isDulWheel() {
    return mainSeries.value == dulWheelScv;
  }

  bool isR1Series() {
    return isDulWheel() && series.value == 1;
  }

  bool isR1() {
    return isDulWheel() && series.value == 1 && type.value == 1;
  }

  bool isV5Series() {
    return isEuc() && series.value == V5;
  }

  bool isV5() {
    return isV5Series() && type.value == 1;
  }

  bool isV5Plus() {
    return isV5Series() && type.value == 2;
  }

  bool isV5F() {
    return isV5Series() && type.value == 3;
  }

  bool isV5D() {
    return isV5Series() && type.value == 4;
  }

  bool isV5SE() {
    return isV5Series() && type.value == 7;
  }

  bool isV5E() {
    return isV5Series() && type.value == 8;
  }

  bool isV5C() {
    return isV5Series() && type.value == 9;
  }

  bool isV8Series() {
    return isEuc() && series.value == V8;
  }

  bool isV8() {
    return isV8Series() && type.value == 1;
  }

  bool isV8F() {
    return isV8Series() && type.value == 3;
  }

  bool isV8S() {
    return isV8Series() && type.value == 4;
  }

  bool isV10Series() {
    return isEuc() && series.value == V10;
  }

  bool isV10Like() {
    return isV10Series() || isV8F() || isV8S();
  }

  bool isV10() {
    return isV10Series() && type.value == 1;
  }

  bool isV10F() {
    return isV10Series() && type.value == 4;
  }

  bool isV11Series() {
    return isEuc() && series.value == V11;
  }

  bool isV11() {
    return isV11Series() && type.value == 1;
  }

  bool isV11Y() {
    return isV11Series() && type.value == 2;
  }

  bool isV12Series() {
    return isEuc() && series.value == V12;
  }

  bool isV12() {
    return isV12Series() && type.value == 1;
  }

  bool isV12HT() {
    return isV12Series() && type.value == 2;
  }

  bool isV12Pro() {
    return isV12Series() && type.value == 3;
  }

  bool isV13Series() {
    return isEuc() && series.value == V13;
  }

  bool isV13() {
    return isV13Series() && type.value == 1;
  }

  bool isV13Pro() {
    return isV13Series() && type.value == 2;
  }

  bool isV14Series() {
    return isEuc() && series.value == V14;
  }

  bool isV14() {
    return isV14Series() && type.value == 1;
  }

  bool isV12sSeries() {
    return isEuc() && series.value == V12S;
  }

  bool isE20Series() {
    return isEuc() && series.value == E20;
  }

  bool isE10Series() {
    return isEuc() && series.value == E10;
  }

  bool isE15Series() {
    return isEuc() && series.value == E15;
  }

  bool isE20() {
    return isE20Series() && type.value == 1;
  }

  bool isE10() {
    return isE10Series() && type.value == 1;
  }

  bool isE15() {
    return isE15Series() && type.value == 1;
  }

  bool isP6Series() {
    return isEuc() && series.value == P6;
  }

  bool isP6() {
    return isP6Series() && type.value == 1;
  }

  bool isV9Series() {
    return isEuc() && series.value == V9;
  }

  bool isV9() {
    return isV9Series() && type.value == 1;
  }

  bool isV6Series() {
    return isEuc() && series.value == V6;
  }

  bool isLA1Series() {
    return isScooter() && series.value == LA1;
  }

  bool isLS1Series() {
    return isScooter() && series.value == LS1;
  }

  bool isRSVeloSeries() {
    return isScooter() && series.value == RS_VELO;
  }

  bool isRSVelo() {
    return isRSVeloSeries() && type.value == 1;
  }

  bool isRsVeloWithTbox(){
    return isRSVeloSeries() && type.value == 2;
  }

  bool isLS1() {
    return isLS1Series() && type.value == 1;
  }

  bool isLS1German() {
    return isLS1Series() && type.value == 2;
  }

  bool isLS1HS() {
    return isLS1Series() && type.value == 3;
  }

  bool isLE1Series() {
    return isScooter() && series.value == LE1;
  }

  /// LE1 V1 常规
  bool isLE1() {
    return isLE1Series() && type.value == 1;
  }

  /// LE1 V1 欧规
  bool isLE1Eu() {
    return isLE1Series() && type.value == 2;
  }

  /// 初始版本的LE1系列，包含LE1常规和LE1欧规版，软硬件供应商为好盈电子
  bool isLE1V1Series() {
    return isLE1() || isLE1Eu();
  }

  /// LE1 V2 常规
  bool isLE1V2() {
    return isLE1Series() && type.value == 3;
  }

  // LE1 V2 欧规
  bool isLE1V2Eu() {
    return isLE1Series() && type.value == 4;
  }

  /// V2版本的LE1系列
  bool isLE1V2Series() {
    return isLE1V2() || isLE1V2Eu();
  }

  bool isLR1Series() {
    return isScooter() && series.value == LR1;
  }

  bool isLR1() {
    return isLR1Series() && type.value == 1;
  }

  bool isLA1() {
    return isLA1Series() && type.value == 3;
  }

  bool isLA1F() {
    return isLA1Series() && type.value == 1;
  }

  bool isLA1FHD() {
    return isLA1Series() && type.value == 4;
  }

  bool isLA1FGerman() {
    return isLA1Series() && type.value == 2;
  }

  bool isLC1Series() {
    return isScooter() && series.value == LC1;
  }

  bool isLC1() {
    return isLC1Series() && !isLC1Pro();
  }

  /// C1国内黑色荣耀合作款
  bool isLC1HCNB() {
    return isLC1Series() && type.value == 1;
  }

  /// C1国内白色荣耀合作款
  bool isLC1HCNW() {
    return isLC1Series() && type.value == 3;
  }

  /// C1欧规黑色荣耀合作款
  bool isLC1HEUB() {
    return isLC1Series() && type.value == 2;
  }

  /// C1欧规白色荣耀合作款
  bool isLC1HEUW() {
    return isLC1Series() && type.value == 4;
  }

  /// C1俄罗斯黑色荣耀合作款
  bool isLC1HRUB() {
    return isLC1Series() && type.value == 6;
  }

  /// C1俄罗斯白色荣耀合作款
  bool isLC1HRUW() {
    return isLC1Series() && type.value == 7;
  }

  /// C1美规乐行自有款
  bool isLC1US() {
    return isLC1Series() && type.value == 9;
  }

  /// C1欧规乐行自有款
  bool isLC1EU() {
    return isLC1Series() && type.value == 10;
  }

  bool isLC1Pro() {
    return isLC1ProEU() || isLC1ProUS();
  }

  bool isLC1ProUS() {
    return isLC1Series() && type.value == 5;
  }

  bool isLC1ProEU() {
    return isLC1Series() && type.value == 8;
  }

  bool isL8Series() {
    return isScooter() && series.value == L8;
  }

  bool isL8() {
    return isL8Series() && type.value == 1;
  }

  bool isL8F() {
    return isL8Series() && type.value == 2;
  }

  bool isL8Fch() {
    return isL8Series() && type.value == 3;
  }

  bool isL8Fno() {
    return isL8Series() && type.value == 4;
  }

  bool isL8D() {
    return isL8Series() && type.value == 5;
  }

  bool isL8S() {
    return isL8Series() && type.value == 6;
  }

  bool isL8SPlus() {
    return isL8Series() && type.value == 7;
  }

  bool isL8DF() {
    return isL8Series() && type.value == 8;
  }

  bool isL8No() {
    return isL8Series() && type.value == 9;
  }

  bool isL8FLike() {
    return isL8Series() &&
        (type.value == 2 ||
            type.value == 3 ||
            type.value == 4 ||
            type.value == 5 ||
            type.value == 6 ||
            type.value == 7 ||
            type.value == 8);
  }

  bool isP1Series() {
    return isEBike() && series.value == P1;
  }

  bool isP1() {
    return isP1Series() && type.value == 1;
  }

  bool isP1F() {
    return isP1Series() && type.value == 2;
  }

  bool isP1SE() {
    return isP1Series() && type.value == 3;
  }

  bool isP1H() {
    return isP1Series() && type.value == 4;
  }

  bool isP2Series() {
    return isEBike() && series.value == P2;
  }

  bool isP2Like() {
    return isP2Series() || isP1H();
  }

  bool isP2() {
    return isP2Series() && type.value == 1;
  }

  bool isP2F() {
    return isP2Series() && type.value == 2;
  }

  bool isP2H() {
    return isP2Series() && type.value == 3;
  }

  bool isP2S() {
    return isP2Series() && type.value == 5;
  }

  bool isE2Series() {
    return isDulWheel() && series.value == E2;
  }

  bool isE3Series() {
    return isDulWheel() && series.value == E3;
  }

  bool isLorinEuc() {
    return isV11Series() ||
        isV12Series() ||
        isV13Series() ||
        isV14Series() ||
        isE20Series() ||
        isV6Series() ||
        isV12sSeries() ||
        isE10Series() ||
        isE15Series() ||
        isP6Series() ||
        isV9Series();
  }

  bool isEzcanEuc() {
    return isV5Series() || isV8Series() || isV10Series();
  }

  bool isLorinScooter() {
    return isLS1Series() ||
        isLC1Series() ||
        isLE1Series() ||
        isLA1Series() ||
        isLR1Series() ||
        isRSVeloSeries();
  }

  bool isEzcanScooter() {
    return isL8Series();
  }

  String name() {
    if (isV11Series()) return "V11";

    if (isV12HT()) return "V12HT";
    if (isV12Pro()) return "V12 Pro";
    if (isV12Series()) return "V12";

    if (isV13Series()) return "V13";
    if (isV14Series()) return "V14";
    if (isE20Series()) return "E20";
    if (isE10Series()) return "E10";
    if (isE15Series()) return "E15";
    if (isP6Series()) return "P6";
    if (isV6Series()) return "V6";
    if (isV9Series()) return "E25";
    if (isV12sSeries()) return "V18";

    if (isV10F()) return "V10F";
    if (isV10Series()) return "V10";

    if (isV8F()) return "V8F";
    if (isV8S()) return "V8S";
    if (isV8Series()) return "V8";

    if (isV5C()) return "V5C";
    if (isV5D()) return "V5D";
    if (isV5E()) return "V5E";
    if (isV5SE()) return "V5E";
    if (isV5F()) return "V5F";
    if (isV5Plus()) return "V5+";
    if (isV5Series()) return "V5";

    if (isLE1Series()) return "Climber";

    if (isLS1Series()) return "S1";

    if (isLA1F()) return "A1F";
    if (isLA1Series()) return "A1";

    if (isLC1Pro()) return "Air Pro";
    if (isLC1Series()) return "Air";

    if (isLR1Series()) return "RS";
    if (isRSVeloSeries()) return "RS-Jet";

    if (isL8D()) return "L8D";
    if (isL8F() || isL8Fno()) return "L8F";
    if (isL8S()) return "L8S";
    if (isL8SPlus()) return "L8S+";
    if (isL8Fno()) return "L8+";
    if (isL8Series()) return "L8";

    if (isP1F()) return "P1F";
    if (isP1H()) return "P1H";
    if (isP1Series()) return "P1";

    if (isP2S()) return "P2S";
    if (isP2F()) return "P2F";
    if (isP2H()) return "P2H";
    if (isP2Series()) return "P2";

    return "Unknown";
  }
}
